const PromiseCopy = function (fn) {
    this.status = "pending"
    this.value = null
    const self = this
    self.onResolvedArr = []
    self.onRejectedArr = []
    const reject = function (x) {
        if (self.status === "pending") {
            self.status = "rejected"
            self.value = x
            self.onRejectedArr.forEach(fn => fn(value))
        }
    }
    const resolve = function (promise, x) {
        let call = false
        if (x === promise) {
            reject(new TypeError('A promise cannot be onFulfilled with itself.'))
        }
        if (x && (Object.prototype.toString.call(x) === "[object,Object]" || typeof x === "function")) {
            try {
                const then = x.then
                if (typeof then === "function") {
                    then.call(x, function (y) {
                        if (call)
                            return
                        call = true
                        resolve(promise, y)
                    }, function (x) {
                        if (call) return
                        reject(x)
                    })
                    return
                }

            } catch (err) {
                if (call) return
                call = true
                reject(err)
            }
        }
        if (x && x instanceof PromiseCopy && x.then === promise.then) {
            if (x.status === "pending") {
                x.onResolvedArr = self.onResolvedArr
                x.onRejectedArr = self.onRejectedArr
            }
            if (x.status === "resolved") {
                self.value = x.value
                self.onResolvedArr.forEach(fn => fn(x.value))
                return
            }
            if (x.status === "rejected") {
                self.value = x.value
                self.onRejectedArr.forEach(fn => fn(x.value))
            }
            return
        }
        if (self.status === "pending") {
            self.status = "resolved"
            self.value = x
            self.onResolvedArr.forEach(fn => fn(x))
        }
    }
    const _resolve = function (x) {
        resolve
    }
    try {
        fn(_resolve, reject)
    } catch (err) {
        setTimeout(() => {
            self.onRejectedArr.forEach(fn => fn(err))
        })
    }

}
PromiseCopy.prototype.then = function (onResolved, onRejected) {
    const self = this
    onResolved = typeof onResolved === "function" ? onResolved : v => v
    onRejected = typeof onRejected === "function" ?
        onRejected : err => { throw err }
    const promise2 = new PromiseCopy((resolve, reject) => {
        if (self.status === "resolved") {
            try {
                x = onResolved(self.value)
                resolve(x)
            } catch (err) {
                reject(err)
            }
        }
        if (self.status === "rejectde") {
            setTimeout(() => {
                try {
                    const x = onRejected(self.value)
                    resolve(x)

                } catch (err) {
                    reject(err)
                }
            })
        }
        if (self.status === "pending") {
            self.onResolvedArr.push((data) => {
                setTimeout(() => {
                    try {
                        const x = onResolved(data)
                        resolve(x)
                    } catch (err) {
                        reject(err)
                    }
                })
            })
            self.onRejectedArr.push((data) => {
                setTimeout(() => {
                    try {
                        const x = onRejected(data)
                        resolve(x)

                    } catch (err) {
                        reject(err)
                    }
                })

            })
        }

    })
    return promise2
}
PromiseCopy.resolve = function (data) {
    return new PromiseCopy((resolve, reject) => {
        resolve(data)
    })
}
PromiseCopy.reject = function (reason) {
    return new PromiseCopy((resolve, reject) => {
        reject(reason)
    })
}
PromiseCopy.all = function (data) {
    let count = 0
    let total = data.length
    let result = []
    return new PromiseCopy((resolve, reject) => {
        for (let i = 0; i < total; i++) {
            data[i].then(
                (res) => {
                    result.push(res);
                    ++count;
                    if (count === total) {
                        resolve(result)
                    }
                }, err => {
                    return reject(err)
                }
            )
        }
    })
}
PromiseCopy.race = function(data){
    const total = data.length
    return new PromiseCopy((resolve, reject)=>{
        for(let i = 0; i <  total; i++){
            data[i].then(res => {
                resolve(res)
            }, err => {
                return reject(res)
            })
        }
    })
}
PromiseCopy.prototype.catch = function(onRejected){
    const self = this
    const newPromise = new PromiseCopy((resolve, reject)=>{
        if(self.status === "onRejected"){
            try{
                setTimeout(()=>{
                    let value = self.value
                    if(typeof onRejected === "function"){
                        value = onRejected(self.value)
                    }
                    resolve(value)
                })
            }catch(err){
                reject(err)
            }
        }
        if(self.status === "pending"){
            self.onRejectedArr.push(data => {
                setTimeout(()=>{
                    try{
                        let value = data
                        if(typeof onRejected === "function"){
                            value = onRejected(data)
                        }
                        resolve(value)
                    }catch(err){
                        reject(err)
                    }
                })
            })
        }
        return newPromise
    })
}
PromiseCopy.prototype.catch = function(onRejected){
    return new PromiseCopy(null, onRejected)
}